package com.winit.deploy.web;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.base.beans.LoginUser;
import com.winit.common.base.web.BaseController;
import com.winit.common.filter.UserInfoUtil;
import com.winit.common.util.ConfigUtil;
import com.winit.common.util.HttpClientUtil;
import com.winit.deploy.bean.AreaStatus;
import com.winit.deploy.bean.DeployArea;
import com.winit.deploy.bean.DeployEnv;
import com.winit.deploy.handler.TaskStatusHandler;
import com.winit.deploy.manager.DeployAuthorizeManager;
import com.winit.deploy.manager.DeployManager;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.bean.ProjectInfo;
import com.winit.project.service.ProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangjian on 16/8/16.
 * 非停机发版
 */
@RestController
@RequestMapping("/deploy")
public class DeployController extends BaseController {

    private static final Logger logger = LoggerFactory.getLogger(DeployController.class);

    @Resource
    private DeployManager deployManager;

    @Resource
    private DeployAuthorizeManager authorizeManager;

    @Resource
    private ProjectService projectService;

    /**
     * 加载发布任务列表
     *
     * @param request
     * @return
     */

    @ResponseBody
    @RequestMapping(value = "/saveEnv", method = RequestMethod.POST)
    public Map<String, Object> saveEnv(@RequestBody DeployEnv deploEnv, HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        logger.info("保存发布环境[" + deploEnv.getName() + "]");
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("保存发布环境[" + deploEnv.getName() + "],获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject data = new JSONObject();
        DeployEnv d = deployManager.getEnvByName(deploEnv.getName());
        if (d == null) {
            logger.error("发布环境[" + deploEnv.getName() + "]不存在");
            rtnMap.put("code", "6");
            rtnMap.put("desc", "发布环境[" + deploEnv.getName() + "]不存在");
            return this.getRtnMap(rtnMap, userInfo, data);
        }
        boolean isRunning = false;
        String runningAreaName = null;
        for (DeployArea deployArea : d.getAreas()) {
            AreaStatus areaStatus = deployManager.getAreaStatus(d.getName(), deployArea.getName());
            if ("running".equals(areaStatus.getStatus())) {
                isRunning = true;
                runningAreaName = deployArea.getName();
                break;
            }
        }
        if (isRunning) {
            logger.error("发布环境[" + d.getName() + "]的区域[" + runningAreaName + "]正在初始化，不要乱动");
            rtnMap.put("code", "7");
            rtnMap.put("desc", "发布环境[" + d.getName() + "]的区域[" + runningAreaName + "]正在初始化，不要乱动");
            return this.getRtnMap(rtnMap, userInfo, data);
        }
        boolean success = deployManager.saveEnv(deploEnv.getName(), deploEnv);
        if (!success) {
            logger.error("保存发布环境[" + deploEnv.getName() + "]失败");
            rtnMap.put("code", "5");
            rtnMap.put("desc", "保存发布环境[" + deploEnv.getName() + "]失败");
        } else {
            logger.info("保存发布环境[" + deploEnv.getName() + "]成功");
            rtnMap.put("code", "0");
            rtnMap.put("desc", "保存发布环境[" + deploEnv.getName() + "]成功");
        }
        return this.getRtnMap(rtnMap, userInfo, data);
    }

    @ResponseBody
    @RequestMapping(value = "/removeArea", method = RequestMethod.POST)
    public Map<String, Object> removeArea(@RequestParam String envName, @RequestParam String areaName, HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        logger.info("删除服务器配置中的区域[" + areaName + "]");
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("删除服务器配置中的区域[" + areaName + "],获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject data = new JSONObject();
        boolean success = deployManager.removeArea(envName, areaName);
        if (!success) {
            logger.error("删除服务器配置中的区域[" + areaName + "]失败");
            rtnMap.put("code", "5");
            rtnMap.put("desc", "删除服务器配置中的区域[" + areaName + "]失败");
        } else {
            logger.info("删除服务器配置中的区域[" + areaName + "]成功");
            rtnMap.put("code", "0");
            rtnMap.put("desc", "删除服务器配置中的区域[" + areaName + "]成功");
        }
        return this.getRtnMap(rtnMap, userInfo, data);
    }

    @ResponseBody
    @RequestMapping(value = "/saveArea/{envName}", method = RequestMethod.POST)
    public Map<String, Object> saveArea(@PathVariable String envName, @RequestBody DeployArea area, HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        logger.info("保存服务器配置中的区域[" + area.getName() + "]");
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("保存服务器配置中的区域[" + area.getName() + "],获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject data = new JSONObject();
        boolean success = deployManager.saveArea(envName, area);
        if (!success) {
            logger.error("保存服务器配置中的区域[" + area.getName() + "]失败");
            rtnMap.put("code", "5");
            rtnMap.put("desc", "保存服务器配置中的区域[" + area.getName() + "]失败");
        } else {
            logger.info("保存服务器配置中的区域[" + area.getName() + "]成功");
            try {
                if (ConfigUtil.getValue("ubarrier_env_list").contains("," + envName + ",")) {
                    HttpClientUtil.doGet(ConfigUtil.getValue("ubarrier_config_url") + "/apps/update?env_name=" + envName);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            rtnMap.put("code", "0");
            rtnMap.put("desc", "保存服务器配置中的区域[" + area.getName() + "]成功");
        }
        return this.getRtnMap(rtnMap, userInfo, data);
    }

    @RequestMapping("/loadEvn")
    @ResponseBody
    public Map<String, Object> loadEnv(HttpServletRequest request, @RequestParam String evnName) {
        logger.info("加载环境[" + evnName + "]");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("加载环境[" + evnName + "],获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject jsonObject = new JSONObject();
        List<DeployEnv> depEnvlist = new ArrayList<>();
        DeployEnv deployEnv = deployManager.getEnvByName(evnName);
        if (deployEnv == null) {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "加载环境[" + evnName + "]失败");
        } else {
            depEnvlist.add(deployEnv);
            jsonObject.put("list", depEnvlist);
            rtnMap.put("code", "0");
        }
        return this.getRtnMap(rtnMap, userInfo, jsonObject);
    }

    @RequestMapping("/loadEnvNames")
    @ResponseBody
    public Map<String, Object> loadEnvNames(HttpServletRequest request) {
        logger.info("加载环境名列表");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("加载环境名列表,获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject jsonObject = new JSONObject();
        List<String> envNames = deployManager.getEnvNames();
        if (envNames == null) {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "加载环境名列表失败");
        } else {
            jsonObject.put("envNames", envNames);
            rtnMap.put("code", "0");
        }
        return this.getRtnMap(rtnMap, userInfo, jsonObject);
    }

    @RequestMapping("/loadAreaStatus")
    @ResponseBody
    public Map<String, Object> loadAreaStatus(HttpServletRequest request,
                                              @RequestParam String evnName,
                                              @RequestParam String areaName) {
        logger.info("加载环境[" + evnName + "]-区域[" + areaName + "]状态");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("加载发布任务列表,获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject jsonObject = new JSONObject();
        AreaStatus areaStatus = deployManager.getAreaStatus(evnName, areaName);
        if (areaStatus == null) {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "加载环境[" + evnName + "]-区域[" + areaName + "]状态失败");
        } else {
            jsonObject.put("areaStatus", areaStatus);
        }
        return this.getRtnMap(rtnMap, userInfo, jsonObject);
    }

    /**
     * 加载任务状态
     *
     * @param request
     * @return
     */
    @RequestMapping("/loadTaskStatus")
    @ResponseBody
    public Map<String, Object> loadTaskStatus(HttpServletRequest request,
                                              @RequestParam String evnName) {
        logger.info("加载区域[" + evnName + "]任务状态开始");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("加载任务状态,获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject jsonObject = deployManager.getEnvTasksStatus(evnName);
        rtnMap.put("code", "0");
        return this.getRtnMap(rtnMap, userInfo, jsonObject);
    }


    @ResponseBody
    @RequestMapping(value = "/saveAreaStatus/{envName}/{areaName}", method = RequestMethod.POST)
    public Map<String, Object> saveAreaStatus(HttpServletRequest request,
                                              @PathVariable String envName, @PathVariable String areaName,
                                              @RequestBody AreaStatus areaStatus) {
        logger.info("保存区域[" + areaName + "]状态");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        boolean success = deployManager.saveAreaStatus(envName, areaName, areaStatus);
        if (success) {
            rtnMap.put("code", "0");
        } else {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "保存区域[" + areaName + "]状态");
        }
        return this.getRtnMap(rtnMap, userInfo, new JSONObject());
    }

    /**
     * 执行任务
     *
     * @param request
     * @return
     */
    @RequestMapping("/doTask")
    @ResponseBody
    public Map<String, Object> doTask(HttpServletRequest request) {
        logger.info("执行任务开始");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("执行任务,获取用户信息为空");
            return this.noUserRtn();
        }
        String envName = request.getParameter("envName");
        String areaName = request.getParameter("areaName");
        String appIds = request.getParameter("appIds");
        String queueName = request.getParameter("queueName");
        String btnType = request.getParameter("btnType");
        String needPrepare = request.getParameter("needPrepare");
        String isCleanRedis = request.getParameter("isCleanRedis");

        Assert.hasText(envName);
        Assert.hasText(areaName);
        Assert.hasText(appIds);
        Assert.hasText(queueName);
        Assert.hasText(btnType);
        Assert.hasText(needPrepare);
        logger.info("envName:" + envName + ",areaName:" + areaName + ",appIds:" + appIds + ",queueName:"
                + queueName + ",btnType:" + btnType + ",needPrepare:" + needPrepare + ",isCleanRedis:" + isCleanRedis);
        if (StringUtils.isEmpty(isCleanRedis)) {
            isCleanRedis = "false";
        }

        List<JSONObject> appId = JSONArray.parseArray(appIds, JSONObject.class);

        if (appId.size() == 0) {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "任务列表为空,请重新选择!");
            return this.getRtnMap(rtnMap, userInfo, new JSONObject());
        }
        //校验工程版本是否存在空值
        for (JSONObject object : appId) {
            String projectName = object.getString("projectName");
            String editionNum = object.getString("editionNum");
            if (StringUtils.isEmpty(projectName)
                    || StringUtils.isEmpty(editionNum)) {
                logger.error("执行任务,存在空值." + object);
                rtnMap.put("code", "1");
                rtnMap.put("desc", "创建任务,发布版本不存在,请重新选择!");
                return this.getRtnMap(rtnMap, userInfo, new JSONObject());
            }

            try {
                if (!projectService.isProjectExist(projectName)) {
                    logger.error("创建任务,工程不存在!工程名=" + projectName);
                    rtnMap.put("code", "1");
                    rtnMap.put("desc", "创建任务,工程不存在!工程名=" + projectName);
                    return this.getRtnMap(rtnMap, userInfo, new JSONObject());
                }
                if (!projectService.isEditionExist(projectName, editionNum)) {
                    logger.error("创建任务,版本不存在!工程名=" + projectName + ",版本号:" + editionNum);
                    rtnMap.put("code", "1");
                    rtnMap.put("desc", "创建任务,版本不存在!工程名=" + projectName + ",版本号:" + editionNum);
                    return this.getRtnMap(rtnMap, userInfo, new JSONObject());
                }
            } catch (Exception e) {
                logger.error("com.winit.deploy.web.DeployController.doTask 判断工程和版本是否存在异常.projectName=" + projectName + ",editionNum=" + editionNum, e);
                rtnMap.put("code", "1");
                rtnMap.put("desc", "判断工程和版本是否存在异常!工程名=" + projectName + ",版本号:" + editionNum + "." + e.getMessage());
                return this.getRtnMap(rtnMap, userInfo, new JSONObject());
            }

            if ("default".equals(editionNum) && !btnType.equals("start") && !btnType.equals("stop")) {
                logger.error("创建任务,default版本不能发布!工程名=" + projectName);
                rtnMap.put("code", "1");
                rtnMap.put("desc", "创建任务,default版本不能发布!工程名=" + projectName);
                return this.getRtnMap(rtnMap, userInfo, new JSONObject());
            }
        }

        try {
            authorizeManager.updateStopDeployTip(envName, false);
            deployManager.doTask(envName, areaName, appId, queueName, btnType, Boolean.parseBoolean(needPrepare), userInfo, Boolean.parseBoolean(isCleanRedis));
            rtnMap.put("code", "0");
        } catch (Exception e) {
            logger.error("创建发布任务异常", e);
            rtnMap.put("code", "1");
            if (e.getMessage().contains("java.net.ConnectException: Connection refused")
                    || e.getMessage().contains("java.net.SocketException: Connection reset")) {
                rtnMap.put("desc", "连接远程终端失败,请重试或联系beetle管理员!");
            } else {
                rtnMap.put("desc", e.getMessage());
            }
        }
        return this.getRtnMap(rtnMap, userInfo, new JSONObject());
    }

    /**
     * 测试用
     * 执行任务
     * @param request
     * @return
     */
//    @RequestMapping("/doTask")
//    @ResponseBody
//    public Map<String, Object> doTask(HttpServletRequest request) {
//        logger.info("执行任务开始");
//        Map<String, Object> rtnMap = new HashMap<>();
//        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
//        if (userInfo == null) {
//            logger.info("执行任务,获取用户信息为空");
//            return this.noUserRtn();
//        }
//        String envName = request.getParameter("envName");
//        String areaName = request.getParameter("areaName");
//        String appIds = request.getParameter("appIds");
//        String queueName = request.getParameter("queueName");
//        String btnType = request.getParameter("btnType");
//
//        Assert.hasText(envName);
//        Assert.hasText(areaName);
//        Assert.hasText(appIds);
//        Assert.hasText(queueName);
//        Assert.hasText(btnType);
//
//        String isConfirm = request.getParameter("isConfirm");
//        String taskType = request.getParameter("taskType");
//
//        List<String> appId = JSONArray.parseArray(appIds,String.class);
//
//        try {
//            DeployManagerTest deployManagerTest = new DeployManagerTest();
//            deployManagerTest.doTaskTest(envName,areaName,appId,queueName,btnType
//                    ,Boolean.parseBoolean(isConfirm),taskType);
//
//            rtnMap.put("code", "0");
//        } catch (Exception e) {
//            rtnMap.put("code", "1");
//            rtnMap.put("desc", e.getMessage());
//        }
//        return this.getRtnMap(rtnMap, userInfo, new JSONObject());
//    }

    /**
     * 弹窗回调
     *
     * @param request
     * @param taskId  任务id
     * @param type    操作类型  0 继续  1 停止
     * @return
     */
    @RequestMapping("/confirmCallBack")
    @ResponseBody
    public Map<String, Object> confirmCallBack(HttpServletRequest request
            , @RequestParam String taskId, @RequestParam String type) {
        logger.info("弹窗回调");
        Map<String, Object> rtnMap = new HashMap<>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("弹窗回调,获取用户信息为空");
            return this.noUserRtn();
        }
        logger.info("弹窗回调,taskId=" + taskId + ",type=" + type);

        if (!"0".equals(type) && !"1".equals(type)) {
            rtnMap.put("code", "1");
            rtnMap.put("desc", "参数type错误");
            return this.getRtnMap(rtnMap, userInfo, new JSONObject());
        }

//        DeployManagerTest deployManagerTest = new DeployManagerTest();
//        deployManagerTest.confirmCallBack(taskId,type);
        deployManager.confirmCallBack(taskId, type);
        rtnMap.put("code", "0");
        return this.getRtnMap(rtnMap, userInfo, new JSONObject());
    }


    @RequestMapping("/cleanAreaTask")
    public void cleanAreaTask(HttpServletRequest request
            , @RequestParam String envName, @RequestParam String areaName, @RequestParam String queueName) {
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            return;
        }
        Assert.hasText(envName);
        Assert.hasText(areaName);
        Assert.hasText(queueName);
        TaskStatusHandler taskStatusHandler = TaskStatusHandler.getInstance();
        taskStatusHandler.cleanAreaTask(envName, areaName, queueName);
    }

    @ResponseBody
    @RequestMapping(value = "/getPassProjectAndVersionsMap", method = RequestMethod.POST)
    public Map<String, Object> getProjectVersionsMap(@RequestBody List<String> projectNames, HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        logger.info("获取发布页工程版本)");
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("获取发布页工程版本,获取用户信息为空");
            return this.noUserRtn();
        }
        JSONObject data = new JSONObject();
        Map versionsMap = new HashMap();
        for (String projectName : projectNames) {
            JSONObject version = new JSONObject();
            try {
                version = projectService.getPassProjectAndEdition(projectName);
            } catch (Exception e) {
                version = null;
            }
            if (null != version) {
                versionsMap.put(projectName, version);
            }
        }
        data.put("versionsMap", versionsMap);
        rtnMap.put("code", "0");
        return this.getRtnMap(rtnMap, userInfo, data);
    }

    @ResponseBody
    @RequestMapping(value = "/getAllTrunkProjects", method = RequestMethod.POST)
    public Map<String, Object> getAllProjects(HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        logger.info("获取主干工程列表");
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.info("获取主干工程列表,获取用户信息为空");
            return this.noUserRtn();
        }
        List<ProjectInfo> projects = new ArrayList<>();
        try {
            projects = projectService.getProjectList("", PackageTypeEnum.ALL, true, false);
        } catch (Exception e) {
            logger.error("getAllTrunkProjects", e);
            projects = null;
        }
        JSONObject data = new JSONObject();
        if (projects == null) {
            logger.error("找不到主干工程列表");
            rtnMap.put("code", "5");
            rtnMap.put("desc", "找不到主干工程列表");
        } else {
            logger.info("获取主干工程列表成功");
            rtnMap.put("code", "0");
            rtnMap.put("desc", "获取主干工程列表成功");
            data.put("projects", projects);
        }
        return this.getRtnMap(rtnMap, userInfo, data);
    }

    @ResponseBody
    @RequestMapping(value = "/autoDeployWho", method = RequestMethod.GET)
    public Map<String, Object> autoDeployWho(HttpServletRequest request) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        LoginUser userInfo = UserInfoUtil.getUserInfo(request);
        if (userInfo == null) {
            logger.error("com.winit.deploy.web.DeployController.autoDeployWho,获取用户信息为空");
            return this.noUserRtn();
        }
        logger.info("com.winit.deploy.web.DeployController.autoDeployWho start");
        try {
            deployManager.autoDeployWho(userInfo,"all");
            rtnMap.put("code", "0");
        } catch (Exception e) {
            e.printStackTrace();
            rtnMap.put("code", "1");
            rtnMap.put("desc", e.getMessage());
        }
        logger.info("com.winit.deploy.web.DeployController.autoDeployWho end " + rtnMap);
        return this.getRtnMap(rtnMap, userInfo, new JSONObject());
    }
}
